Categories
Node.js Best Practices

Node.js Best Practices — Tokens and Secrets

Spread the love

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at some best practices we should follow when writing Node apps.

Support Blacklisting JWTs

We should be able to blacklist JSON web tokens so that we can lock out malicious users,

There are no mechanisms to do this for most systems.

We can add a list of untrusted tokens to prevent them from logging in.

Prevent Brute-Force Attacks Against Authorization

Brute-force attacks against authorization can be prevented with rate limiting.

For instance, we can limit the login attempts by the block repeated failed login requests.

Run Node.js as a Non-root User

Non-root user should be used to run Node apps.

This way, they can do whatever they want in our system.

We can bake that into the Docker image or set it with the -u flag.

Limit Payload Size Using a Reverse Proxy or a Middleware

Payload size should be limited to avoid overloading our systems.

This can help with preventing DOS attacks.

If the requests’ body size is small, less damage can be done.

We can set express body parser to accept small size payloads with the limit option.

Avoid JavaScript eval Statements

We can avoid JavaScript eval statements.

They’re insecure since code is run from a string.

It also makes optimizations and debugging impossible.

setTimeout , setInterval , and the Function constructor also run code from strings.

So we should avoid passing strings to them as well.

Prevent Evil RegEx from Overloading Single Thread Execution

There’s some regex that we should avoid.

To make data validation easy, we can use a library like validator.js or look up safe regex we can use with safe-regex to detect vulnerable regex patterns to avoid.

Bad regex can make our app susceptible to DOS attacks that block the event loop.

This will make our app hang.

Avoid Module Loading Using a Variable

We shouldn’t call require with a variable.

This way, we can’t let attackers pass anything into the require function.

For instance, instead of writing:

const insecure = require(helperPath);

We write:

const uploadHelpers = require('./helpers/upload');

This also applies to other paths we pass in like when we read a file with fs.readFile .

Run Unsafe Code in a Sandbox

If we have any unsafe code, we should run them in a sandbox.

This way, they can’t get to the outside world and potentially do damage.

NPM packages can be sandboxed. A dedicated process can also be sandboxed.

Take Extra Care When Working with Child Processes

If we run child processes in our Node app, we should sanitize the command string so that we can run without risks.

If we don’t escape them, then attackers can run anything they want, which can be catastrophic.

Hide Error Details from Clients

If there are any details about errors that expose the internals of our system, we should hide them from clients.

This way, the chance of attackers finding ways to attack our app is much lower.

Anything like paths, stack traces, and more should be hidden.

Conclusion

We should hide sensitive data, isolate risky code, and escape any strings that are potentially malicious.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *